import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/material.dart';
import 'package:grint/utils/whisper.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
import 'package:grint/utils/local_store.dart';
import 'package:grint/utils/file_manager.dart';
import 'package:grint/entity/check_in_record.dart';

class RecordState {
  final DateTime selectedDate;
  final DateTime currentMonth;
  final int currentYear;
  final String recordContent;
  final String? selectedImagePath;

  const RecordState({
    required this.selectedDate,
    required this.currentMonth,
    required this.currentYear,
    required this.recordContent,
    this.selectedImagePath,
  });

  RecordState copyWith({
    DateTime? selectedDate,
    DateTime? currentMonth,
    int? currentYear,
    String? recordContent,
    String? selectedImagePath,
    bool clearImagePath = false,
  }) {
    return RecordState(
      selectedDate: selectedDate ?? this.selectedDate,
      currentMonth: currentMonth ?? this.currentMonth,
      currentYear: currentYear ?? this.currentYear,
      recordContent: recordContent ?? this.recordContent,
      selectedImagePath:
          clearImagePath ? null : (selectedImagePath ?? this.selectedImagePath),
    );
  }
}

class RecordCubit extends Cubit<RecordState> {
  final LocalStore _localStore = LocalStore();
  final DataVault _fileManager = DataVault();

  RecordCubit()
    : super(
        RecordState(
          selectedDate: DateTime.now(),
          currentMonth: DateTime.now(),
          currentYear: DateTime.now().year,
          recordContent: '',
          selectedImagePath: null,
        ),
      ) {
    _initializeAndLoadData();
  }

  Future<void> _initializeAndLoadData() async {
    await _localStore.init();
    await _loadRecordForSelectedDate();
  }

  void changeYear(int year) {
    emit(
      state.copyWith(
        currentYear: year,
        currentMonth: DateTime(year, state.currentMonth.month, 1),
      ),
    );
  }

  void changeMonth(int month) {
    emit(state.copyWith(currentMonth: DateTime(state.currentYear, month, 1)));
  }

  Future<void> selectDate(DateTime date) async {
    emit(state.copyWith(selectedDate: date));
    await _loadRecordForSelectedDate();
  }

  Future<void> _loadRecordForSelectedDate() async {
    await _localStore.init();
    final dateKey = _formatDateKey(state.selectedDate);
    final recordData = _localStore.getObjectValue('check_in_$dateKey');

    if (recordData != null) {
      try {
        final record = CheckInRecord.fromJson(recordData);
        emit(
          state.copyWith(
            recordContent: record.content,
            selectedImagePath: record.imagePath,
          ),
        );
      } catch (e) {
        emit(state.copyWith(recordContent: '', clearImagePath: true));
      }
    } else {
      emit(state.copyWith(recordContent: '', clearImagePath: true));
    }
  }

  String _formatDateKey(DateTime date) {
    return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}';
  }

  Future<void> pickAndSaveImage(BuildContext context) async {
    final List<AssetEntity>? assets = await AssetPicker.pickAssets(
      context,
      pickerConfig: const AssetPickerConfig(
        maxAssets: 1,
        requestType: RequestType.image,
      ),
    );
    if (assets == null || assets.isEmpty) return;
    final asset = assets.first;
    final file = await asset.file;
    if (file == null) return;

    final fileName = _fileManager.buildTimeStamp(state.selectedDate);

    final savedPath = await _fileManager.storeAsset(file.path, fileName);

    if (savedPath != null) {
      emit(state.copyWith(selectedImagePath: savedPath));
      Whisper.murmur('Image selected');
    } else {
      Whisper.hiss('Failed to save image');
    }
  }

  void clearSelectedImage() {
    emit(state.copyWith(clearImagePath: true));
  }

  void updateRecordContent(String content) {
    emit(state.copyWith(recordContent: content));
  }

  Future<bool> checkInWithContent() async {
    if (state.recordContent.isEmpty || state.selectedImagePath == null) {
      Whisper.hiss('Please input content and select image');
      return false;
    }

    final today = DateTime.now();
    if (!_isSameDay(state.selectedDate, today)) {
      Whisper.hiss('Can only check in for today');
      return false;
    }

    if (isCheckedIn(state.selectedDate)) {
      Whisper.hiss('Already checked in today');
      return false;
    }

    try {
      final record = CheckInRecord(
        date: _formatDateKey(state.selectedDate),
        imagePath: state.selectedImagePath!,
        content: state.recordContent,
        createdAt: DateTime.now(),
      );

      final dateKey = _formatDateKey(state.selectedDate);
      await _localStore.setObjectValue('check_in_$dateKey', record.toJson());

      emit(state.copyWith(recordContent: '', clearImagePath: true));
      Whisper.murmur('Check in successful!');
      return true;
    } catch (e) {
      Whisper.hiss('Check in failed, please try again');
      return false;
    }
  }

  bool _isSameDay(DateTime date1, DateTime date2) {
    return date1.year == date2.year &&
        date1.month == date2.month &&
        date1.day == date2.day;
  }

  bool isCheckedIn(DateTime date) {
    final dateKey = _formatDateKey(date);
    final recordData = _localStore.getObjectValue('check_in_$dateKey');
    return recordData != null;
  }

  int getDaysInCurrentMonth() {
    return DateTime(state.currentYear, state.currentMonth.month + 1, 0).day;
  }

  int getFirstDayOfMonth() {
    return DateTime(state.currentYear, state.currentMonth.month, 1).weekday;
  }
}
